core: Add --tar-autocreate-parents option for commit
authorColin Walters <walters@verbum.org>
Fri, 23 Dec 2011 11:49:04 +0000 (06:49 -0500)
committerColin Walters <walters@verbum.org>
Fri, 23 Dec 2011 11:49:04 +0000 (06:49 -0500)
The tar files we're making of artifacts don't include parent
directories.  Now we could change the builder to make them, but we can
also just autocreate them on import.  Mode 0755 with no xattrs seems
OK here.

src/libostree/ostree-mutable-tree.c
src/libostree/ostree-mutable-tree.h
src/libostree/ostree-repo.c
src/libostree/ostree-repo.h
src/ostree/ot-builtin-commit.c
tests/t0006-libarchive.sh

index ca8be1ee6add6177f74af0c1910f3c5d42e3d4d1..5f63f113f510c48c5aed6f6a533366c133a035a0 100644 (file)
@@ -221,6 +221,55 @@ ostree_mutable_tree_lookup (OstreeMutableTree   *self,
   return ret;
 }
 
+gboolean
+ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree  *self,
+                                        GPtrArray          *split_path,
+                                        const char         *metadata_checksum,
+                                        OstreeMutableTree **out_parent,
+                                        GError            **error)
+{
+  gboolean ret = FALSE;
+  int i;
+  OstreeMutableTree *ret_parent = NULL;
+  OstreeMutableTree *subdir = self;
+
+  g_assert (metadata_checksum != NULL);
+
+  if (!self->metadata_checksum)
+    ostree_mutable_tree_set_metadata_checksum (self, metadata_checksum);
+
+  for (i = 0; i+1 < split_path->len; i++)
+    {
+      OstreeMutableTree *next;
+      const char *name = split_path->pdata[i];
+
+      if (g_hash_table_lookup (subdir->files, name))
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Can't replace file with directory: %s", name);
+          goto out;
+        }
+
+      next = g_hash_table_lookup (subdir->subdirs, name);
+      if (!next) 
+        {
+          next = ostree_mutable_tree_new ();
+          ostree_mutable_tree_set_metadata_checksum (next, metadata_checksum);
+          g_hash_table_insert (subdir->subdirs, g_strdup (name), next);
+        }
+      
+      subdir = next;
+    }
+
+  ret_parent = g_object_ref (subdir);
+
+  ret = TRUE;
+  ot_transfer_out_value (out_parent, &ret_parent);
+ out:
+  g_clear_object (&ret_parent);
+  return ret;
+}
+
 gboolean
 ostree_mutable_tree_walk (OstreeMutableTree     *self,
                           GPtrArray             *split_path,
index 413da028456df2052320d6d85c41b5436f14df5f..e47964d137cd1b299551eebbef5a215d1fe96811 100644 (file)
@@ -77,6 +77,13 @@ gboolean ostree_mutable_tree_lookup (OstreeMutableTree   *self,
                                      OstreeMutableTree  **out_subdir,
                                      GError             **error);
 
+gboolean
+ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree  *self,
+                                        GPtrArray          *split_path,
+                                        const char         *metadata_checksum,
+                                        OstreeMutableTree **out_parent,
+                                        GError            **error);
+
 gboolean ostree_mutable_tree_walk (OstreeMutableTree   *self,
                                    GPtrArray           *split_path,
                                    guint                start,
index 80b818127a30328ea6f192814f4476085a8085d7..71bf05553f23c38ea8b0db94c83f08b91b0a2223 100644 (file)
@@ -1585,6 +1585,7 @@ ostree_repo_stage_mtree (OstreeRepo           *self,
       while (g_hash_table_iter_next (&hash_iter, &key, &value))
         {
           const char *name = key;
+          const char *metadata_checksum;
           OstreeMutableTree *child_dir = value;
           char *child_dir_contents_checksum;
 
@@ -1592,10 +1593,13 @@ ostree_repo_stage_mtree (OstreeRepo           *self,
                                         cancellable, error))
             goto out;
       
+          g_assert (child_dir_contents_checksum);
           g_hash_table_replace (dir_contents_checksums, g_strdup (name),
                                 child_dir_contents_checksum); /* Transfer ownership */
+          metadata_checksum = ostree_mutable_tree_get_metadata_checksum (child_dir);
+          g_assert (metadata_checksum);
           g_hash_table_replace (dir_metadata_checksums, g_strdup (name),
-                                g_strdup (ostree_mutable_tree_get_metadata_checksum (child_dir)));
+                                g_strdup (metadata_checksum));
         }
     
       serialized_tree = create_tree_variant_from_hashes (ostree_mutable_tree_get_files (mtree),
@@ -1709,6 +1713,7 @@ stage_libarchive_entry_to_mtree (OstreeRepo           *self,
                                  struct archive       *a,
                                  struct archive_entry *entry,
                                  OstreeRepoCommitModifier *modifier,
+                                 const char               *tmp_dir_checksum,
                                  GCancellable         *cancellable,
                                  GError              **error)
 {
@@ -1738,8 +1743,19 @@ stage_libarchive_entry_to_mtree (OstreeRepo           *self,
     }
   else
     {
-      if (!ostree_mutable_tree_walk (root, split_path, 0, &parent, error))
-        goto out;
+      if (tmp_dir_checksum)
+        {
+          if (!ostree_mutable_tree_ensure_parent_dirs (root, split_path,
+                                                       tmp_dir_checksum,
+                                                       &parent,
+                                                       error))
+            goto out;
+        }
+      else
+        {
+          if (!ostree_mutable_tree_walk (root, split_path, 0, &parent, error))
+            goto out;
+        }
       basename = (char*)split_path->pdata[split_path->len-1];
     }
 
@@ -1854,18 +1870,21 @@ stage_libarchive_entry_to_mtree (OstreeRepo           *self,
 #endif
                           
 gboolean
-ostree_repo_stage_archive_to_mtree (OstreeRepo           *self,
-                                    GFile                *archive_f,
-                                    OstreeMutableTree    *root,
-                                    OstreeRepoCommitModifier *modifier,
-                                    GCancellable         *cancellable,
-                                    GError              **error)
+ostree_repo_stage_archive_to_mtree (OstreeRepo                *self,
+                                    GFile                     *archive_f,
+                                    OstreeMutableTree         *root,
+                                    OstreeRepoCommitModifier  *modifier,
+                                    gboolean                   autocreate_parents,
+                                    GCancellable             *cancellable,
+                                    GError                  **error)
 {
 #ifdef HAVE_LIBARCHIVE
   gboolean ret = FALSE;
-  struct archive *a;
+  struct archive *a = NULL;
   struct archive_entry *entry;
   int r;
+  GFileInfo *tmp_dir_info = NULL;
+  GChecksum *tmp_dir_checksum = NULL;
 
   a = archive_read_new ();
   archive_read_support_compression_all (a);
@@ -1887,7 +1906,22 @@ ostree_repo_stage_archive_to_mtree (OstreeRepo           *self,
           goto out;
         }
 
-      if (!stage_libarchive_entry_to_mtree (self, root, a, entry, modifier, cancellable, error))
+      if (autocreate_parents && !tmp_dir_checksum)
+        {
+          tmp_dir_info = g_file_info_new ();
+          
+          g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::uid", archive_entry_uid (entry));
+          g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::gid", archive_entry_gid (entry));
+          g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::mode", 0755 | S_IFDIR);
+          
+          if (!stage_directory_meta (self, tmp_dir_info, NULL, &tmp_dir_checksum, cancellable, error))
+            goto out;
+        }
+
+      if (!stage_libarchive_entry_to_mtree (self, root, a,
+                                            entry, modifier,
+                                            autocreate_parents ? g_checksum_get_string (tmp_dir_checksum) : NULL,
+                                            cancellable, error))
         goto out;
     }
   if (archive_read_close (a) != ARCHIVE_OK)
@@ -1898,7 +1932,10 @@ ostree_repo_stage_archive_to_mtree (OstreeRepo           *self,
 
   ret = TRUE;
  out:
-  (void)archive_read_close (a);
+  g_clear_object (&tmp_dir_info);
+  ot_clear_checksum (&tmp_dir_checksum);
+  if (a)
+    (void)archive_read_close (a);
   return ret;
 #else
   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
index 08ebd58c1aab3d33981c6dddc2f1d233d915b167..3777d8400b5dc7ac1fbe64499a258d5153c27728 100644 (file)
@@ -158,6 +158,7 @@ gboolean      ostree_repo_stage_archive_to_mtree (OstreeRepo         *self,
                                                   GFile              *archive,
                                                   OstreeMutableTree  *tree,
                                                   OstreeRepoCommitModifier *modifier,
+                                                  gboolean            autocreate_parents,
                                                   GCancellable *cancellable,
                                                   GError      **error);
 
index 5fcc0371baf44e9b6bf5babd3babd2b019f960c9..8e525ef206524f528e9acc95beb3535f3cd8013f 100644 (file)
@@ -36,6 +36,7 @@ static char *body;
 static char *parent;
 static char *branch;
 static gboolean skip_if_unchanged;
+static gboolean tar_autocreate_parents;
 static char **trees;
 static gint owner_uid = -1;
 static gint owner_gid = -1;
@@ -50,6 +51,7 @@ static GOptionEntry options[] = {
   { "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &trees, "Overlay the given argument as a tree", "NAME" },
   { "owner-uid", 0, 0, G_OPTION_ARG_INT, &owner_uid, "Set file ownership user id", "UID" },
   { "owner-gid", 0, 0, G_OPTION_ARG_INT, &owner_gid, "Set file ownership group id", "GID" },
+  { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL },
   { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL },
   { NULL }
 };
@@ -187,6 +189,7 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error)
             {
               arg = ot_gfile_new_for_path (tree);
               if (!ostree_repo_stage_archive_to_mtree (repo, arg, mtree, modifier,
+                                                       tar_autocreate_parents,
                                                        cancellable, error))
                 goto out;
             }
index 4173c97aa3dcef456e42a2954a41d3526e1acc34..06a0bf9cc2f84340336bac06693fa79753bde603 100755 (executable)
@@ -100,3 +100,13 @@ assert_file_has_content otherfile "not overwritten"
 assert_file_has_content subdir/original "original"
 assert_file_has_content subdir/new "new"
 echo "ok tar multicommit contents"
+
+cd ${test_tmpdir}/multicommit-files
+tar -c -C files1 -z -f partial.tar.gz subdir/original
+$OSTREE commit -s 'partial' -b partial --tar-autocreate-parents --tree=tar=partial.tar.gz
+echo "ok tar partial commit"
+
+cd ${test_tmpdir}
+$OSTREE checkout partial partial-checkout
+cd partial-checkout
+assert_file_has_content subdir/original "original"